﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Algobox.JuicyLib.Collections.Generics
{
    public class SyncDictionary<K, V> : IDictionary<K, V>
    {
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary
        /// class that is empty, has the default initial capacity, and uses the 
        /// default equality comparer for the key type.
        /// </summary>
        public SyncDictionary()
        {
            m_Dictionary = new Dictionary<K, V>();
        }
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary class that contains elements copied from the specified System.Collections.Generic.IDictionary and uses the default equality comparer for the key type.
        /// </summary>
        /// <param name="dictionary">The System.Collections.Generic.IDictionary whose elements are copied to the new System.Collections.Generic.Dictionary.</param>
        /// <exception cref="System.ArgumentNullException">dictionary is null</exception>
        /// <exception cref="System.ArgumentException">dictionary contains one or more duplicate keys</exception>
        public SyncDictionary(IDictionary<K, V> dictionary)
        {
            m_Dictionary = new Dictionary<K, V>(dictionary);
        }
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary class that is empty, has the default initial capacity, and uses the specified System.Collections.Generic.IEqualityComparer.
        /// </summary>
        /// <param name="comparer">The System.Collections.Generic.IEqualityComparer implementation to use when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer for the type of the key.</param>
        public SyncDictionary(IEqualityComparer<K> comparer)
        {
            m_Dictionary = new Dictionary<K, V>(comparer);
        }
         /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary class that is empty, has the specified initial capacity, and uses the default equality comparer for the key type.
        /// </summary>
        /// <param name="capacity">The initial number of elements that the System.Collections.Generic.Dictionary can contain.</param>
        /// <exception cref="System.ArgumentOutOfRangeException">capacity is less than 0</exception>
        public SyncDictionary(int capacity)
        {
            m_Dictionary = new Dictionary<K, V>(capacity);
        }
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary class that contains elements copied from the specified System.Collections.Generic.IDictionary and uses the specified System.Collections.Generic.IEqualityComparer.
        /// </summary>
        /// <param name="dictionary">The System.Collections.Generic.IDictionary whose elements are copied to the new System.Collections.Generic.Dictionary.</param>
        /// <param name="comparer">The System.Collections.Generic.IEqualityComparer implementation to use when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer for the type of the key.</param>
        /// <exception cref="System.ArgumentNullException">Dictionary is Null</exception>         
        /// <exception cref="System.ArgumentException">Dictionary contains one or more duplicate keys</exception>
        public SyncDictionary(IDictionary<K, V> dictionary, IEqualityComparer<K> comparer)
        {
            m_Dictionary = new Dictionary<K, V>(dictionary, comparer);
        }           
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary class that is empty, has the specified initial capacity, and uses the specified System.Collections.Generic.IEqualityComparer.
        /// </summary>
        /// <param name="capacity">The initial number of elements that the System.Collections.Generic.Dictionary can contain.</param>
        /// <param name="comparer">The System.Collections.Generic.IEqualityComparer implementation to use when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer for the type of the key.</param>
        /// <exception cref="System.ArgumentOutOfRangeException">capacity is less than 0</exception>
        public SyncDictionary(int capacity, IEqualityComparer<K> comparer)
        {
            m_Dictionary = new Dictionary<K, V>(capacity, comparer);
        }


        ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();

        Dictionary<K, V> m_Dictionary;
        

        #region IDictionary<K,V> Members

        public void Add(K key, V value)
        {
            m_Lock.EnterWriteLock();
            m_Dictionary.Add(key, value);
            m_Lock.ExitWriteLock();
        }

        public bool ContainsKey(K key)
        {
            m_Lock.EnterReadLock();
            bool result = m_Dictionary.ContainsKey(key);
            m_Lock.ExitReadLock();
            return result;
        }

        public ICollection<K> Keys
        {
            get
            {
                m_Lock.EnterReadLock();
                try
                {
                    return m_Dictionary.Keys;
                }
                finally
                {
                    m_Lock.ExitReadLock();
                }
            }
        }

        public bool Remove(K key)
        {
            m_Lock.EnterWriteLock();
            bool result = m_Dictionary.Remove(key);
            m_Lock.ExitWriteLock();
            return result;
        }

        public bool TryGetValue(K key, out V value)
        {
            m_Lock.EnterReadLock();
            try
            {
                return m_Dictionary.TryGetValue(key, out value);
            }
            finally
            {
                m_Lock.ExitReadLock();
            }
        }

        public ICollection<V> Values
        {
            get
            {
                m_Lock.EnterReadLock();
                try
                {
                    return m_Dictionary.Values;
                }
                finally
                {
                    m_Lock.ExitReadLock();
                }
            }
        }

        public V this[K key]
        {
            get
            {
                m_Lock.EnterReadLock();
                try
                {
                    return m_Dictionary[key];
                }
                finally
                {
                    m_Lock.ExitReadLock();
                }
            }
            set
            {
                m_Lock.EnterWriteLock();
                try
                {
                    m_Dictionary[key] = value;
                }
                finally
                {
                    m_Lock.ExitWriteLock();
                }
            }
        }

        #endregion

        #region ICollection<KeyValuePair<K,V>> Members

        public void Add(KeyValuePair<K, V> item)
        {
            m_Lock.EnterWriteLock();
            ((ICollection<KeyValuePair<K, V>>)m_Dictionary).Add(item);            
            m_Lock.ExitWriteLock();
        }

        public void Clear()
        {
            m_Lock.EnterWriteLock();
            m_Dictionary.Clear();
            m_Lock.ExitWriteLock();
        }

        public bool Contains(KeyValuePair<K, V> item)
        {
            m_Lock.EnterReadLock();
            bool result = m_Dictionary.Contains(item);
            m_Lock.ExitReadLock();
            return result;
        }

        public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
        {
            m_Lock.EnterWriteLock();
            ((ICollection<KeyValuePair<K, V>>)m_Dictionary).CopyTo(array, arrayIndex);
            m_Lock.ExitWriteLock();
        }

        public int Count
        {
            get
            {
                m_Lock.EnterReadLock();
                int result = m_Dictionary.Count;
                m_Lock.ExitReadLock();
                return result;
            }
        }

        public bool IsReadOnly
        {
            get
            {
                m_Lock.EnterReadLock();
                bool result = ((ICollection<KeyValuePair<K, V>>)m_Dictionary).IsReadOnly;
                m_Lock.ExitReadLock();
                return result;
            }
        }

        public bool Remove(KeyValuePair<K, V> item)
        {
            m_Lock.EnterWriteLock();
            bool result = ((ICollection<KeyValuePair<K, V>>)m_Dictionary).Remove(item);
            m_Lock.ExitWriteLock();
            return result;
        }

        #endregion

        #region IEnumerable<KeyValuePair<K,V>> Members

        public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
        {
            m_Lock.EnterReadLock();
            try
            {
                return ((IEnumerable<KeyValuePair<K,V>>)m_Dictionary).GetEnumerator();
            }
            finally
            {
                m_Lock.ExitReadLock();
            }
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            m_Lock.EnterReadLock();
            try
            {
                return m_Dictionary.GetEnumerator();
            }
            finally
            {
                m_Lock.ExitReadLock();
            }
        }

        #endregion
    }
}
